home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockWebServiceManager.js < prev    next >
Text File  |  2007-10-18  |  25KB  |  696 lines

  1. // vim: ts=2 sw=2 expandtab cindent
  2. //
  3. // BEGIN FLOCK GPL
  4. // 
  5. // Copyright Flock Inc. 2005-2007
  6. // http://flock.com
  7. // 
  8. // This file may be used under the terms of of the
  9. // GNU General Public License Version 2 or later (the "GPL"),
  10. // http://www.gnu.org/licenses/gpl.html
  11. // 
  12. // Software distributed under the License is distributed on an "AS IS" basis,
  13. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. // for the specific language governing rights and limitations under the
  15. // License.
  16. // 
  17. // END FLOCK GPL
  18.  
  19. const Cc = Components.classes;
  20. const Ci = Components.interfaces;
  21. const Cr = Components.results;
  22.  
  23. const WEBSVCMGR_CID = Components.ID("{23d157f0-5941-11db-b0de-0800200c9a66}");
  24. const WEBSVCMGR_CONTRACTID = "@flock.com/webservice-manager;1";
  25.  
  26. //const OBS_TOPIC_FLOCKDATAREADY = "flock-data-ready";
  27. const OBS_TOPIC_FLOCKDOCREADY = "FlockDocumentReady";
  28. const OBS_TOPIC_FORMSUBMIT = "earlyformsubmit";
  29. const OBS_TOPIC_XPCOMSHUTDOWN = "xpcom-shutdown";
  30.  
  31.  
  32. // ========================================================
  33. // ========== BEGIN flockWebServiceManager class ==========
  34. // ========================================================
  35.  
  36. function flockWebServiceManager()
  37. {
  38.   this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
  39.   this._logger.init("webServiceManager");
  40.   this._logger.info("Created Web Service Manager Object");
  41.  
  42.   // Associative array where keys are service contract IDs and values are URNs
  43.   this.mAllServicesByContract = [];
  44.  
  45.   // Associative array where keys are URNs and values are XPCOM services
  46.   this.mInstantiatedServices = [];
  47.  
  48.   // Cache the .domains properties of each service, by URN
  49.   this.mDomains = [];
  50.  
  51.   // mTempIgnore is used to keep track of which services the user has elected
  52.   // NOT to enable Flock support for during this browser session
  53.   this.mTempIgnore = [];
  54.  
  55.   // mListeners is the array of flockIWebServiceAccountListeners
  56.   this.mListeners = [];
  57.   
  58.   // mKeepAccounts is an associative array of service URNs to dates, used by
  59.   // autoKeepAccountForService()
  60.   this.mKeepAccounts = [];
  61.  
  62.   this.obs = Cc["@mozilla.org/observer-service;1"]
  63.                .getService(Ci.nsIObserverService);
  64.   //this.obs.addObserver(this, OBS_TOPIC_FLOCKDATAREADY, false);
  65.   this.obs.addObserver(this, OBS_TOPIC_XPCOMSHUTDOWN, false);
  66.   // addObserver calls for FLOCKDOCREADY and FORMSUBMIT are in this.setup()
  67.  
  68.   this.mEnabled = true;
  69.   this.mRegisteredEvents = false;
  70.  
  71.   this._metrics = Cc["@flock.com/metrics-service;1"]
  72.                   .getService(Ci.flockIMetricsService);
  73.   
  74.   this.setup();
  75. }
  76.  
  77.  
  78. // BEGIN nsISupports interface
  79. flockWebServiceManager.prototype.QueryInterface =
  80. function flockWebServiceManager_QueryInterface(aIID)
  81. {
  82.   if ( !aIID.equals(Ci.nsISupports) &&
  83.        !aIID.equals(Ci.nsIObserver) &&
  84.        !aIID.equals(Ci.flockIWebServiceManager) )
  85.   {
  86.     throw Cr.NS_ERROR_NO_INTERFACE;
  87.   }
  88.   return this;
  89. }
  90. // END nsISupports interface
  91.  
  92.  
  93. // BEGIN nsIObserver interface
  94. flockWebServiceManager.prototype.observe =
  95. function flockWebServiceManager_observe(aSubject, aTopic, aData)
  96. {
  97.   switch (aTopic) {
  98.     //case OBS_TOPIC_FLOCKDATAREADY:
  99.       //this.obs.removeObserver(this, OBS_TOPIC_FLOCKDATAREADY);
  100.       //this.setup();
  101.       //break;
  102.  
  103.     case OBS_TOPIC_FORMSUBMIT:
  104.       this.onFormSubmit(aSubject, aData);
  105.       break;
  106.  
  107.     case OBS_TOPIC_FLOCKDOCREADY:
  108.       this.onDocumentReady(aSubject, aData);
  109.       break;
  110.  
  111.     case OBS_TOPIC_XPCOMSHUTDOWN:
  112.       if (this.mRegisteredEvents) {
  113.         this.obs.removeObserver(this, OBS_TOPIC_FLOCKDOCREADY);
  114.         this.obs.removeObserver(this, OBS_TOPIC_FORMSUBMIT);
  115.       }
  116.       this.obs.removeObserver(this, OBS_TOPIC_XPCOMSHUTDOWN);
  117.       break;
  118.   }
  119. }
  120. // END nsIObserver interface
  121.  
  122.  
  123. // BEGIN flockIWebServiceManager interface
  124. flockWebServiceManager.prototype.registerWebService =
  125. function flockWebServiceManager_registerWebService(aService)
  126. {
  127.   aService.QueryInterface(Ci.flockIManageableWebService);
  128.   this._logger.info(".registerWebService(contract: "+aService.contractId+" URN: "+aService.urn+")");
  129.   this.mAllServicesByContract[aService.contractId] = aService.urn;
  130.   this.mInstantiatedServices[aService.urn] = aService;
  131.   this.checkFirstRun(aService);
  132.   this.checkPasswordsForService(aService);
  133. }
  134.  
  135. flockWebServiceManager.prototype.unregisterWebService =
  136. function flockWebServiceManager_unregsiterWebService(aService)
  137. {
  138.   aService.QueryInterface(Ci.flockIManageableWebService);
  139.   this._logger.info(".unregisterWebService("+aService.urn+")");
  140.   this.mInstantiatedServices[aService.urn] = undefined;
  141. }
  142.  
  143. flockWebServiceManager.prototype.addListener = 
  144. function flockWebServiceManager_addListener(aListener)
  145. {
  146.   aListener.QueryInterface(Ci.flockIWebServiceAccountListener);
  147.   this.mListeners.push(aListener);
  148.   this._logger.info(".addListener() ["+this.mListeners.length+"]");
  149. }
  150.  
  151. flockWebServiceManager.prototype.removeListener = 
  152. function flockWebServiceManager_removeListener(aListener)
  153. {
  154.   for (var i = 0; i < this.mListeners.length; ++i) {
  155.     if (aListener == this.mListeners[i]) {
  156.       this.mListeners.splice(i, 1);
  157.       break;
  158.     }
  159.   }
  160. }
  161.  
  162. flockWebServiceManager.prototype.autoKeepAccountForService =
  163. function flockWebServiceManager_autoKeepAccountForService(aServiceURN)
  164. {
  165.   var stopTime = new Date();
  166.   stopTime.setHours(stopTime.getHours() + 1);
  167.   this.mKeepAccounts[aServiceURN] = stopTime.getTime();
  168. }
  169. // END flockIWebServiceManager interface
  170.  
  171.  
  172. // BEGIN internal helper functions
  173. flockWebServiceManager.prototype.setup =
  174. function flockWebServiceManager_setup()
  175. {
  176.   this._logger.info(".setup()");
  177.  
  178.   this.coop = Cc["@flock.com/singleton;1"]
  179.               .getService(Ci.flockISingleton)
  180.               .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  181.               .wrappedJSObject;
  182.  
  183.   this.acUtils = Cc["@flock.com/account-utils;1"]
  184.                    .getService(Ci.flockIAccountUtils);
  185.  
  186.   this._profiler = Cc["@flock.com/profiler;1"].getService(Ci.flockIProfiler);
  187.  
  188.   var prefSvc = Cc["@mozilla.org/preferences-service;1"]
  189.                   .getService(Ci.nsIPrefService);
  190.   var prefs = prefSvc.getBranch(null);
  191.   this.firstRunPrefs = prefSvc.getBranch("flock.service.firstruncomplete.");
  192.   this.svcConfPrefs = prefSvc.getBranch("flock.service.confirmation.");
  193.  
  194.   this.mEnabled = true;
  195.   if (prefs.getPrefType("flock.service.webservicemanager.enabled")) {
  196.     this.mEnabled = prefs.getBoolPref("flock.service.webservicemanager.enabled");
  197.   }
  198.   if (!this.mEnabled) { return; }
  199.  
  200.   this.obs.addObserver(this, OBS_TOPIC_FORMSUBMIT, false);
  201.   this.obs.addObserver(this, OBS_TOPIC_FLOCKDOCREADY, false);
  202.   this.mRegisteredEvents = true;
  203.  
  204.   // Web Service Manager is responsible for determining when to instantiate any
  205.   // services in the "wsm-startup" category.
  206.   var catMgr = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  207.   var svcEnum = catMgr.enumerateCategory("wsm-startup");
  208.   var firstRun = ( !this.firstRunPrefs.getPrefType("webservicemanager") ||
  209.                    !this.firstRunPrefs.getBoolPref("webservicemanager") );
  210.   this._logger.info((firstRun) ? "First run" : "NOT first run");
  211.   while (svcEnum.hasMoreElements()) {
  212.     var entry = svcEnum.getNext().QueryInterface(Ci.nsISupportsCString);
  213.     if (!entry) continue;
  214.     var contractID = catMgr.getCategoryEntry("wsm-startup", entry.data);
  215.     this._logger.info("checking "+contractID);
  216.     // Always instantiate web services components on first run, or when an
  217.     // account has already been configured
  218.     var shouldInstantiate = ( firstRun ||
  219.       this.coop.Account.find({serviceId: contractID}).length );
  220.     var findSvc;
  221.     if (!shouldInstantiate) {
  222.       // If it doesn't exist in the RDF, then it was not properly initialized
  223.       // last time, so make sure it gets instantiated now
  224.       findSvc = this.coop.Service.find({serviceId: contractID});
  225.       if (findSvc.length == 0) { shouldInstantiate = true; }
  226.     }
  227.     if (shouldInstantiate) {
  228.       var service = this.instantiateWebService(contractID);
  229.       this.checkFirstRun(service);
  230.     } else {
  231.       // There's still a possibility that this is the first run for this
  232.       // service -- eg. if it's from an extention
  233.       this._logger.info("Decided NOT to instantiate "+contractID);
  234.       this.mAllServicesByContract[contractID] = findSvc[0].id();
  235.       this.checkFirstRun(null, contractID);
  236.     }
  237.   }
  238.   this.firstRunPrefs.setBoolPref("webservicemanager", true);
  239. }
  240.  
  241. /**
  242.  * Every web service component must get instantiated at least once - generally
  243.  * on first-run - so that it can update the RDF, etc.
  244.  */
  245. flockWebServiceManager.prototype.checkFirstRun =
  246. function flcokWebServiceManager_checkFirstRun(aService, aServiceContractID)
  247. {
  248.   var serviceURN = (aService) ? aService.urn
  249.     : this.coop.Service.find({serviceId: aServiceContractID})[0].id();
  250.  
  251.   this._logger.info(".checkFirstRun() "+serviceURN);
  252.   if ( !this.firstRunPrefs.getPrefType(serviceURN) ||
  253.        !this.firstRunPrefs.getBoolPref(serviceURN) )
  254.   {
  255.     // This is the first time we are running with this service, so ensure
  256.     // that it is instantiated
  257.     if (!aService) {
  258.       aService = this.instantiateWebService(aServiceContractID);
  259.     }
  260.     this.firstRunPrefs.setBoolPref(serviceURN, true);
  261.   }
  262. }
  263.  
  264. flockWebServiceManager.prototype.instantiateWebService =
  265. function flockWebServiceManager_instantiateWebService(aServiceContractID)
  266. {
  267.   this._logger.info(".instantiateWebService('"+aServiceContractID+"')");
  268.   var service = Cc[aServiceContractID]
  269.     .getService(Ci.flockIManageableWebService);
  270.   this.mAllServicesByContract[aServiceContractID] = service.urn;
  271.   this.mInstantiatedServices[service.urn] = service;
  272.   this.checkPasswordsForService(service);
  273.   return service;
  274. }
  275.  
  276. flockWebServiceManager.prototype.checkPasswordsForService =
  277. function flockWebServiceManager_checkPasswordsForService(aService)
  278. {
  279.   if (aService.needPassword) {
  280.     // This service requires that we have a password stored in order to have
  281.     // a properly configured account.  Check if we have accounts, and if they
  282.     // don't have passwords then log them out in order to force the user to
  283.     // log in again.
  284.     var c_accounts = this.coop.Account.find({serviceId: aService.contractId});
  285.     var missingAPassword = false;
  286.     for (var i = 0; i < c_accounts.length; i++) {
  287.       var c_acct = c_accounts[i];
  288.       var pw = this.acUtils.getPassword(aService.urn+":"+c_acct.accountId);
  289.       if (!pw) {
  290.         missingAPassword = true;
  291.         if (c_acct.isAuthenticated) {
  292.           aService.logout();
  293.           this.acUtils.markAllAccountsAsLoggedOut(aService.contractId);
  294.           return;
  295.         }
  296.       }
  297.     }
  298.     if (missingAPassword) {
  299.       // We are missing a password, but we don't know whether that account is
  300.       // currently logged in or not.  If it's an account that the user never
  301.       // uses, then we don't want to force logout here (because we could be
  302.       // logging them out of the account they actually DO use)
  303.       if (c_accounts.length == 1) {
  304.         // But in this case there's only one account.  This must be the one
  305.         // we're missing the password for.  So we want to log the service out,
  306.         // regardless.  This will force the user to log in again, so we can
  307.         // re-capture that password.
  308.         aService.logout();
  309.         this.acUtils.markAllAccountsAsLoggedOut(aService.contractId);
  310.       }
  311.     }
  312.   }
  313. }
  314.  
  315. flockWebServiceManager.prototype.onFormSubmit =
  316. function flockWebServiceManager_onFormSubmit(aForm, aData)
  317. {
  318.   this._logger.info(".onFormSubmit('"+aData+"')");
  319.   var url = aForm.ownerDocument.QueryInterface(Ci.nsIDOMHTMLDocument).URL;
  320.   if (!this.mIOS) {
  321.     this.mIOS = Cc["@mozilla.org/network/io-service;1"]
  322.                   .getService(Ci.nsIIOService);
  323.   }
  324.   var uri = this.mIOS.newURI(url, null, null);
  325.  
  326.   for (var contractID in this.mAllServicesByContract) {
  327.     this._logger.info("try "+contractID);
  328.  
  329.     // Check the domain
  330.     var serviceURN = this.mAllServicesByContract[contractID];
  331.     this._logger.info(" - URN is "+serviceURN);
  332.     if (!this.testDomains(serviceURN, uri.host)) {
  333.       this._logger.info("NO MATCH on domains for "+serviceURN);
  334.       continue;
  335.     }
  336.     this._logger.info("form domains MATCH for "+serviceURN);
  337.  
  338.     // The domain matched, so ensure this service is instantiated
  339.     var service = this.mInstantiatedServices[serviceURN];
  340.     if (!service) {
  341.       service = this.instantiateWebService(contractID);
  342.     }
  343.  
  344.     // Ask the service if it owns this form being submitted
  345.     if (!service.ownsLoginForm(aForm)) { continue; }
  346.     this._logger.info(" service '"+service.urn+"' says it owns this form.");
  347.  
  348.     var pw = service.getCredentialsFromForm(aForm);
  349.     if (pw) {
  350.       // The user has just tried to log in, sign up for, or change their
  351.       // password on this service.  We don't know which account it was for,
  352.       // or if they were successful yet -- so for now, store the password
  353.       // temporarily, associated with the service URN.
  354.       this._logger.info(" saving TEMPORARY password for '"+service.urn+"'");
  355.       var origin = pw.QueryInterface(Ci.flockIPassword);
  356.       this.acUtils.setTempPassword(service.urn, pw.user, pw.password, origin.formType);
  357.     } else {
  358.       this._logger.info(" service'"+service.urn+"' could not retrieve login info, nothing we can do :(");
  359.     }
  360.     // This form has already been claimed by a service, don't give the other
  361.     // services a chance to claim it.
  362.     break;
  363.   }
  364. }
  365.  
  366. flockWebServiceManager.prototype.onDocumentReady =
  367. function flockWebServiceManager_onDocumentReady(aDocument, aURL)
  368. {
  369.   var profilerEvt = this._profiler.profileEventStart("onDocumentReady");
  370.   this._logger.info(".onDocumentReady('"+aURL+"')");
  371.  
  372.   // flockIManageableWebServices only know how to deal with HTML documents
  373.   if (!(aDocument instanceof Ci.nsIDOMHTMLDocument)) {
  374.     this._profiler.profileEventEnd(profilerEvt, aURL);
  375.     return;
  376.   }
  377.  
  378.   if (!this.mIOS) {
  379.     this.mIOS = Cc["@mozilla.org/network/io-service;1"]
  380.                   .getService(Ci.nsIIOService);
  381.   }
  382.   var uri = this.mIOS.newURI(aURL, null, null);
  383.   var isOwned = false;
  384.  
  385.   // Function to alert user if there's a need to re-login
  386.   var inst = this;
  387.   var notifyPasswordMissing = function wsm_passwordMissing(aService) {
  388.     for (var i = 0; i < inst.mListeners.length; ++i) {
  389.       if (inst.mListeners[i].onAccountPasswordMissing) {
  390.         inst.mListeners[i].onAccountPasswordMissing(aService, aDocument);
  391.       }
  392.     }
  393.   };
  394.  
  395.   // Loop through all the services
  396.   for (var contractID in this.mAllServicesByContract) {
  397.     this._logger.info("try "+contractID);
  398.  
  399.     // Check the domain
  400.     var serviceURN = this.mAllServicesByContract[contractID];
  401.     this._logger.info(" - URN is "+serviceURN);
  402.     if (!this.testDomains(serviceURN, uri.host)) { continue; }
  403.     this._logger.info("domains MATCH for "+serviceURN);
  404.  
  405.     // The domain matched, so ensure this service is instantiated
  406.     var service = this.mInstantiatedServices[serviceURN];
  407.     if (!service) {
  408.       service = this.instantiateWebService(contractID);
  409.     }
  410.  
  411.     // Ask the service if it actually cares about this document
  412.     if (!service.ownsDocument(aDocument)) { continue; }
  413.     this._logger.info(" service '"+service.urn+"' says IT OWNS this document.");
  414.     isOwned = true;
  415.  
  416.     // We now know the service cares about this document, so next check if
  417.     // it's a login landing page
  418.     if (service.docRepresentsSuccessfulLogin(aDocument)) {
  419.       this._logger.info(" service '"+service.urn+"' says this page represents a successful login!");
  420.  
  421.       // User has just logged in -- see which account
  422.       var acct_id = service.getAccountIDFromDocument(aDocument);
  423.  
  424.       if (acct_id) {
  425.         if (this.getServiceConfirmation(service.urn)) {
  426.           // We have detected an account ID on this page, and furthermore the
  427.           // service confirmation has not forbade us from trying to use this
  428.           // service.  So lets's see if we need to create an account.
  429.  
  430.           // If we have a temp password stored for this service (from the
  431.           // onFormSubmit call), then we now know that we can associate it with
  432.           // this account ID
  433.           var pw = this.acUtils.getTempPassword(service.urn);
  434.           if (pw) {
  435.             var origin = pw.QueryInterface(Ci.flockIPassword);
  436.             if (origin.formType == "signup") {
  437.               this._metrics.report("Account-Signup", service.shortName);
  438.             }
  439.  
  440.             this.acUtils.setTempPassword(service.urn + ":" + acct_id, pw.user,
  441.                                          pw.password, origin.formType);
  442.             this.acUtils.clearTempPassword(service.urn);
  443.           }
  444.  
  445.           // The service has told us the account ID represented by the
  446.           // document, but that account might not actually exist in the RDF.
  447.           var acctURN = this.acUtils.getAccountURNById(service.urn, acct_id);
  448.  
  449.           if (!acctURN) {
  450.             // Flock does not yet know about this account
  451.             if (pw || !service.needPassword) {
  452.               // We have a password, or else this service does not require a
  453.               // password in order for us to configure an account.
  454.               this._logger.info(" set up new temporary account: " + acct_id);
  455.               this.setUpAccount(service, acct_id, aDocument);
  456.             } else {
  457.               // We don't have a stored password. That may be due to migrated
  458.               // cookies (bug 6404).
  459.               this._logger.info(" no password associated to the account");
  460.               notifyPasswordMissing(service);
  461.             }
  462.           } else if (this.acUtils.isTransient(acctURN)) {
  463.             // The account is set up, but transient.  We should give the user
  464.             // the option to keep it, unless they have already explicitly
  465.             // dismissed that notification.
  466.             this._logger.info(" found existing temp account: " + acct_id);
  467.             this.checkNotifyAccount(aDocument, service.getAccount(acctURN));
  468.           } else {
  469.             // The account is already set up and is non-transient.  The only
  470.             // thing to do is make sure we don't have an out-of-date password.
  471.             this._logger.info(" found existing account: "+acct_id);
  472.             if (pw) {
  473.               this.acUtils.makeTempPasswordPermanent(service.urn+":"+acct_id);
  474.             }
  475.           }
  476.         } else {
  477.           this._logger.info(" user indicated to ignore this service");
  478.         }
  479.       } else {
  480.         this._logger.info(" unable to find account ID on this page");
  481.         // This is a somewhat broken state.  We know we're logged in, but we
  482.         // can't tell which account.  Our only hope is to make the user log
  483.         // out and log in again.  Using the "no password" notification to do
  484.         // that.
  485.         notifyPasswordMissing(service);
  486.       }
  487.     }
  488.  
  489.     // Give the service a chance to update the auth state of its account(s)
  490.     service.updateAccountStatusFromDocument(aDocument);
  491.  
  492.     // Give media services a chance to detect media
  493.     var isMediaService = true;
  494.     try {
  495.       service.QueryInterface(Ci.flockIMediaWebService);
  496.     } catch (ex) {
  497.       isMediaService = false;
  498.     }
  499.     if (isMediaService) {
  500.       service.decorateForMedia(aDocument);
  501.     }
  502.     this._profiler.profileEventEnd(profilerEvt, aURL);
  503.     return;
  504.   }
  505.   // If no service owns the doc, notify explore button menu to redraw
  506.   if (!isOwned) {
  507.     this.obs.notifyObservers(aDocument, "media", "media:update");
  508.   }
  509.   this._profiler.profileEventEnd(profilerEvt, aURL);
  510. }
  511.  
  512. flockWebServiceManager.prototype.testDomains =
  513. function flockWebServiceManager_testDomains(aServiceURN, aHost)
  514. {
  515.   var domains = this.mDomains;
  516.   if (!domains[aServiceURN]) {
  517.     var domainList = this.coop.get(aServiceURN).domains;
  518.     var domainArr = [];
  519.     if (domainList) {
  520.       this._logger.info("got domains for '"+aServiceURN+"': "+domainList);
  521.       domains[aServiceURN] = domainList.split(",");
  522.     }
  523.   }
  524.   var domainArr = domains[aServiceURN];
  525.   if (!domainArr || domainArr.length == 0) {
  526.     return true;
  527.   }
  528.   for (var i = 0; i < domainArr.length; i++) {
  529.     var domain = domainArr[i];
  530.     if (aHost == domain) return true;
  531.     var idx = aHost.indexOf("."+domain);
  532.     if ((idx > 0) && ((idx + domain.length + 1) == aHost.length)) return true;
  533.   }
  534.   this._logger.info("domains did not match for "+aServiceURN);
  535.   return false;
  536. }
  537.  
  538. flockWebServiceManager.prototype.getServiceConfirmation =
  539. function flockWebServiceManager_getServiceConfirmation(aURN)
  540. {
  541.   if (this.mTempIgnore[aURN]) {
  542.     return false;
  543.   }
  544.   var askUser = true;  // default value is to ask the user
  545.   if (this.svcConfPrefs.getPrefType(aURN)) {
  546.     askUser = this.svcConfPrefs.getBoolPref(aURN);
  547.   }
  548.   return askUser;
  549. }
  550.  
  551. flockWebServiceManager.prototype.setServiceConfirmation =
  552. function flockWebServiceManager_setServiceConfirmation(aUrn, aValue)
  553. {
  554.   this.svcConfPrefs.setBoolPref(aUrn, aValue);
  555. }
  556.  
  557. flockWebServiceManager.prototype.setUpAccount =
  558. function flockWebServiceManager_setUpAccount(aService, aNewAccountID, aDocument)
  559. {
  560.   this._logger.info("setUpAccount('"+aService.shortName+"', '"+aNewAccountID+"')");
  561.   var inst = this;
  562.  
  563.   var authListener = {
  564.     onSuccess: function (aAccount, aTopic) {
  565.       inst.notifyListeners(aAccount, "accountAuthorized");
  566.     },
  567.     onError: function (aSubject, aTopic, aError) {
  568.       inst._logger.debug("setUpAccount() authListener.onError()");
  569.     }
  570.   };
  571.  
  572.   var creationListener = {
  573.     onSuccess: function (aAccount, aTopic) {
  574.       aAccount.QueryInterface(Ci.flockIWebServiceAccount);
  575.       inst.checkNotifyAccount(aDocument, aAccount);
  576.       aAccount.activate(authListener);
  577.     },
  578.     onError: function (aSubject, aTopic, aError) {
  579.       inst._logger.debug("setUpAccount() creationListener.onError()");
  580.     }
  581.   };
  582.  
  583.   // Accounts are created as 'transient' by default, unless
  584.   // autoKeepAccountForService() has been called recently
  585.   var setTransient = true;
  586.   var stopTime = this.mKeepAccounts[aService.urn];
  587.   if (stopTime) {
  588.     var nowTime = (new Date()).getTime();
  589.     if (nowTime < stopTime) {
  590.       setTransient = false;
  591.     } else {
  592.       this.mKeepAccounts[aService.urn] = undefined;
  593.     }
  594.   }
  595.  
  596.   var acct = aService.addAccountById(aNewAccountID, setTransient, creationListener);
  597.   this._metrics.report("Account-Add", aService.shortName);
  598.   if (!setTransient) {
  599.     acct.keep();
  600.   }
  601.   this._logger.info("acct is: "+acct);
  602. }
  603.  
  604. flockWebServiceManager.prototype.checkNotifyAccount =
  605. function flockWebServiceManager_checkNotifyAccount(aDocument, aAccount)
  606. {
  607.   aDocument.QueryInterface(Ci.nsIDOMDocument);
  608.   aAccount.QueryInterface(Ci.flockIWebServiceAccount);
  609.   this._logger.info("checkNotifyAccount('"+aAccount.urn+"')");
  610.   this.notifyListeners(aAccount, "accountCreated", aDocument);
  611. }
  612.  
  613. flockWebServiceManager.prototype.notifyListeners =
  614. function flockWebServiceManager_notifyListeners(aAccount, aEventName, aDocument)
  615. {
  616.   switch (aEventName) {
  617.     case "accountCreated":
  618.       for (var i = 0; i < this.mListeners.length; ++i) {
  619.         this.mListeners[i].onAccountCreated(aAccount, aDocument);
  620.       }
  621.       break;
  622.     case "accountPasswordMissing":
  623.       for (var i = 0; i < this.mListeners.length; ++i) {
  624.         if (this.mListeners[i].onAccountPasswordMissing)
  625.           this.mListeners[i].onAccountPasswordMissing(null, aDocument);
  626.       }
  627.       break;
  628.     case "accountAuthorized":
  629.       for (var i = 0; i < this.mListeners.length; ++i) {
  630.         this.mListeners[i].onAccountAuthChange(aAccount);
  631.       }
  632.       break;
  633.     default:
  634.       break;
  635.   }
  636. }
  637. // ========== END flockWebServiceManager class ==========
  638.  
  639.  
  640.  
  641. // ========== BEGIN XPCOM Module support ==========
  642.  
  643. // BEGIN flockWebServiceManagerModule object
  644. var flockWebServiceManagerModule = {};
  645.  
  646. flockWebServiceManagerModule.registerSelf =
  647. function flockWebServiceManagerModule_registerSelf(compMgr, fileSpec, location, type)
  648. {
  649.   compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  650.   compMgr.registerFactoryLocation( WEBSVCMGR_CID, 
  651.                                    "Flock Web Service Manager JS Component",
  652.                                    WEBSVCMGR_CONTRACTID, 
  653.                                    fileSpec, 
  654.                                    location,
  655.                                    type );
  656. }
  657.  
  658. flockWebServiceManagerModule.getClassObject =
  659. function flockWebServiceManagerModule_getClassObject(compMgr, cid, iid)
  660. {
  661.   if (!cid.equals(WEBSVCMGR_CID))
  662.     throw Cr.NS_ERROR_NO_INTERFACE;
  663.   if (!iid.equals(Ci.nsIFactory))
  664.     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  665.   return flockWebServiceManagerFactory;
  666. }
  667.  
  668. flockWebServiceManagerModule.canUnload =
  669. function flockWebServiceManagerModule_canUnload(compMgr)
  670. {
  671.   return true;
  672. }
  673. // END flockWebServiceManagerModule object
  674.  
  675.  
  676. // BEGIN flockWebServiceManagerFactory object
  677. var flockWebServiceManagerFactory = new Object();
  678.  
  679. flockWebServiceManagerFactory.createInstance =
  680. function flockWebServiceManagerFactory_createInstance(outer, iid)
  681. {
  682.   if (outer != null) {
  683.     throw Cr.NS_ERROR_NO_AGGREGATION;
  684.   }
  685.   return (new flockWebServiceManager()).QueryInterface(iid);
  686. }
  687. // END flockWebServiceManagerFactory object
  688.  
  689.  
  690. // NS module entry point
  691. function NSGetModule(compMgr, fileSpec) {
  692.   return flockWebServiceManagerModule;
  693. }
  694.  
  695. // ========== END XPCOM module support ==========
  696.